/*
 * Main.cpp
 *
 *  Created on: Jan 15, 2011
 *      Author: LyonsDesktop
 */

#include <iostream>
#include <time.h>
#include <sstream>
//#include "Extern.h"

//#include "Main.h"
#include "Datasets/Formats/CSV.h"
//#include "Datasets/Formats/Dataspec.h"
#include "Datasets/Dataset.h"

#include "RegionDiscovery/Fitness/Additive/Purity.h"
#include "RegionDiscovery/Fitness/Additive/AdditiveFitnessFunction.h"
#include "RegionDiscovery/Neighbourhood/Neighbourhood.h"
#include "RegionDiscovery/Neighbourhood/OperatorBasedNeighbourhood.h"
#include "RegionDiscovery/DistanceFunctions/ProximitySearch.h"
#include "RegionDiscovery/DistanceFunctions/DistanceFunction.h"

//#include "RegionDiscovery/SRIDHCR/SRIDHCR.h"
//#include "RegionDiscovery/SCMRG/SCMRG.h"
#include "RegionDiscovery/Clever.h"

#ifdef FRAMEWORKMEMORYTRACKER
#  include "Extern.h"
#  define new new (__FILE__, __LINE__)
#endif

#ifdef FRAMEWORKPROFILER
#  include "Extern.h"
#endif

using namespace std;
using namespace CLEVER;
using namespace CLEVER::Datasets;
using namespace CLEVER::RegionDiscovery;

string interestingnessF = "purity";
int p = 15;
int q = 12;
double rEta = 2.0;
double rthreshold = 1.2;
double rbeta = 1.4;
int useDistanceMatrix = 0;
int clusterIDIndex = 1;
int num_runs = 1;
int useDoubleArrayDataset = 0;
unsigned _NumExamples = 0;
int init_k = 0;
int isLoopPara = 0;
double maxTime = 0;
int maxReplacement = 0;
int incrementalUpdate = 0;
//static bool isYahooDataset=false;
////! A utility class to benchmark the sample application.
//class CStopWatch
//{
//public:
//    //CStopWatch() { QueryPerformanceFrequency(&PerfFreq); }
//    CStopWatch() {}
//    //void Start() { start.QuadPart = 0; QueryPerformanceCounter(&start); }
//    void Start() { clock_gettime(CLOCK_REALTIME, &start);}   //need to add rt library to the linker
//    //void Stop() { end.QuadPart = 0; QueryPerformanceCounter(&end); }
//    void Stop() { clock_gettime(CLOCK_REALTIME, &end);}		 //need to add rt library to the linker
//    /*long double GetDuration() {
//      long double duration=(end.QuadPart - start.QuadPart) / long double(PerfFreq.QuadPart);
//      return  duration;
//    }*/
//    long double GetDuration(){
//      timespec temp;
//      if ((end.tv_nsec-start.tv_nsec)<0) {
//                      temp.tv_sec = end.tv_sec-start.tv_sec-1;
//                      temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;//a nanosecond is 10E-9 second
//              } else {
//                      temp.tv_sec = end.tv_sec-start.tv_sec;
//                      temp.tv_nsec = end.tv_nsec-start.tv_nsec;
//              }
//
//      long double duration=temp.tv_sec+(temp.tv_nsec/1000000000.0);//in seconds, resolution up to nanosecond
//      return duration;
//    }
//
//private:
//    timespec start, end, PerfFreq;
//};

//! Custom interesting function for the sample application.
template<typename T>
class VarianceHigh : public CLEVER::RegionDiscovery::Fitness::Additive::Interestingness<T>
{
public:
	double DatasetVariance;
	virtual double Fitness(CLEVER::Datasets::DoubleArrayDataset * rData,  NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{
		double variance = FindVariance(rData, UseIndex, IndexVal);

		if (variance / DatasetVariance < rthreshold) {
			return 0;
		} else   {
			double res = variance / DatasetVariance - rthreshold;
			if (rEta != 1.0) { res = pow(res, rEta); }
			return res;
		}
	}


	virtual double Fitness(CLEVER::Datasets::Dataset<T> * rData,  NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{   //PROFILE_FUNC

		double variance = FindVariance(rData, UseIndex, IndexVal);

		if (variance / DatasetVariance < rthreshold) {
			return 0;
		} else   {
			double res = variance / DatasetVariance - rthreshold;
			if (rEta != 1.0) { res = pow(res, rEta); }
			return res;
		}
	}


	virtual double Fitness(std::vector<double> & rData, NumericDataset * gData, CLEVER::Datasets::NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{
		double variance = FindVariance(rData, gData, UseIndex, IndexVal);

		if (variance / DatasetVariance < rthreshold) {
			return 0;
		} else   {
			double res = variance / DatasetVariance - rthreshold;
			if (rEta != 1.0) { res = pow(res, rEta); }
			return res;
		}
	}


	double FindVariance(std::vector<double> & rData, NumericDataset * gData, int UseIndex = -1, int IndexVal = -1)
	{   //PROFILE_FUNC
		double variance = 0;
		double nSize = rData.size();

		if (nSize < 2) { return variance; }

		int metasize = (int)gData->MetaData.data.size();
		double nsum = 0;
		double nsumsq = 0;

		if (UseIndex > -1) { //compute the variance of a cluster
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData[i] == IndexVal) {
					++nSize;
					double fval = gData->GetMeta(i, 0); //Assume to compute the variance of the meta attribute[1]
					nsum += fval;
					nsumsq += fval * fval;
				}
			}
		} else   { //compute the variance for all clusters (whole dataset)
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				++nSize;
				double fval = gData->GetMeta(i, 0);
				nsum += fval;
				nsumsq += fval * fval;
			}
		}

		//variance = (nsumsq - ((nsum * nsum) / nSize)) / (nSize - 1.0);
		variance = (nsumsq / (nSize - 1)) - std::pow(nsum / (nSize - 1), 2);  // mean of the square minus the square of the mean
		return variance;
	}


	//UseIndex: the index of the cluster attribute in metadata
	//IndexVal: the cluster ID of the interested cluster(compute its variance)
	double FindVariance(CLEVER::Datasets::Dataset<T> * rData, int UseIndex = -1, int IndexVal = -1)
	{   //PROFILE_FUNC
		double variance = 0;
		double nSize = rData->Size();

		if (nSize < 2) { return variance; }

		int metasize = (int)rData->MetaData.data.size();
		double nsum = 0;
		double nsumsq = 0;

		if (UseIndex > -1) { //compute the variance of a cluster
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData->GetMeta(i, UseIndex) == IndexVal) {
					++nSize;
					double fval = rData->GetMeta(i, 0); //Assume to compute the variance of the meta attribute[0]
					nsum += fval;
					nsumsq += fval * fval;
				}
			}
		} else   { //compute the variance for all clusters (whole dataset)
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				++nSize;
				double fval = rData->GetMeta(i, 0);
				nsum += fval;
				nsumsq += fval * fval;
			}
		}

		//variance = (nsumsq - ((nsum * nsum) / nSize)) / (nSize - 1.0);
		variance = (nsumsq / (nSize - 1)) - std::pow(nsum / (nSize - 1), 2);  // mean of the square minus the square of the mean
		return variance;
	}


	double FindVariance(CLEVER::Datasets::DoubleArrayDataset * rData, int UseIndex = -1, int IndexVal = -1)
	{   //PROFILE_FUNC
		double variance = 0;
		double nSize = rData->Size();

		if (nSize < 2) { return variance; }

		int metasize = (int)rData->Size();
		double nsum = 0;
		double nsumsq = 0;

		if (UseIndex > -1) { //compute the variance of a cluster
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData->GetMeta(i, UseIndex) == IndexVal) {
					//					std::cout<<"example:"<<i<<" meta[0]="<<rData->GetMeta(i,0)<<" meta[1]="<<rData->GetMeta(i,1)<<std::endl;
					++nSize;
					double fval = rData->GetMeta(i, 0); //Assume to compute the variance of the meta attribute[1]
					nsum += fval;
					nsumsq += fval * fval;
				}
			}
		} else   { //compute the variance for all clusters (whole dataset)
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				++nSize;
				double fval = rData->GetMeta(i, 0);
				nsum += fval;
				nsumsq += fval * fval;
			}
		}

		//variance = (nsumsq - ((nsum * nsum) / nSize)) / (nSize - 1.0);
		variance = (nsumsq / (nSize - 1)) - std::pow(nsum / (nSize - 1), 2);  // mean of the square minus the square of the mean
		return variance;
	}


	virtual void Precompute(CLEVER::Datasets::Dataset<T> * rData)
	{   //PROFILE_FUNC

	}


};

template<typename T>
class AverageDistanceToMedoid : public CLEVER::RegionDiscovery::Fitness::Additive::Interestingness<T>
{
public:
	static const long pP = 199;
	DistanceFunctions::MinkowskiDistanceFunction * tDist;
	AverageDistanceToMedoid (DistanceFunctions::MinkowskiDistanceFunction * distfunc) : tDist(distfunc){}
	~AverageDistanceToMedoid(){}
	virtual double Fitness(DoubleArrayDataset * rData,  NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{
		int nSize = rData->Size();        //size of a cluster

		//int metasize = (int)rData->MetaData.data.size();
		int metasize = nSize;
		double nVal = 0;

		if (UseIndex > -1) {       //index of cluster ID = UseIndex
			NumericDataset * medoid = repSet;

			//					int repID;
			//					for(unsigned i=0;i<repSet.size();i++)
			//					{
			//						if((int)rData->GetMeta(repSet[i],UseIndex) == IndexVal)
			//						{
			//							rData->CloneExample(rData,repSet[i],medoid);
			//						}
			//					}

			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				//cout<<"id:"<<rData->GetMeta(i, 0)<<"--"<<(int)rData->GetMeta(i, UseIndex)<<":"<<IndexVal<<" medoid Id:"<<medoid->GetMeta(IndexVal,0)<<  endl;
				if ((int)rData->GetMeta(i, UseIndex) == IndexVal) {
					++nSize;
					//nVal += rData->GetMeta(i, 0);
					nVal += tDist->Distance(rData, i, medoid, IndexVal);       //total distance from examples to the representative
				}
			}
			//delete medoid;
		} else   {
			for (int i = 0; i < metasize; ++i) {
				//if (UseIndex > -1 && (int)rData->GetMeta(i, UseIndex) != IndexVal)
				//{ continue; }
				nVal += rData->GetMeta(i, 0);
			}
		}


		double fitness = 0;
		double t = (double)nVal / (double)nSize;         // t is the average distance between members to medoid

		if (t > rthreshold) {
			fitness = pP - t > 0 ? pP - t : 0;  //fitness = Max(0, pP-avgDist)
			if (rEta != 1.0) { fitness = pow(fitness, rEta); }
		}

		return fitness;
	}


	virtual void Precompute(DoubleArrayDataset * rData)
	{   //PROFILE_FUNC

	}


	virtual double Fitness(CLEVER::Datasets::Dataset<T> * rData, NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{
		int nSize = rData->Size();        //size of a cluster
		//int metasize = (int)rData->MetaData.data.size();
		int metasize = nSize;
		double nVal = 0;

		if (UseIndex > -1) {       //index of cluster ID = UseIndex
			NumericDataset * medoid = repSet; new NumericDataset();
			//					medoid->MetaData.attributes=rData->MetaData.attributes;
			//					medoid->RealData.attributes=rData->RealData.attributes;
			//					int repID;
			//					for(unsigned i=0;i<repSet.size();i++)
			//					{
			//						if((int)rData->GetMeta(repSet[i],UseIndex) == IndexVal)
			//						{
			//							rData->CloneExample(rData,repSet[i],medoid);
			//						}
			//					}

			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData->GetMeta(i, UseIndex) == IndexVal) {
					++nSize;
					//nVal += rData->GetMeta(i, 0);
					nVal += tDist->Distance(rData, i, medoid, IndexVal);       //total distance from examples to the representative
				}
			}
			//delete medoid;
		} else   {
			for (int i = 0; i < metasize; ++i) {
				//if (UseIndex > -1 && (int)rData->GetMeta(i, UseIndex) != IndexVal)
				//{ continue; }
				nVal += rData->GetMeta(i, 0);
			}
		}


		double fitness = 0;
		double t = (double)nVal / (double)nSize;         // t is the average distance between members to medoid

		if (t > rthreshold) {
			fitness = pP - t > 0 ? pP - t : 0;  //fitness = Max(0, pP-avgDist)
			if (rEta != 1.0) { fitness = pow(fitness, rEta); }
		}

		return fitness;
	}


	virtual void Precompute(CLEVER::Datasets::Dataset<T> * rData)
	{   //PROFILE_FUNC

	}


	virtual double Fitness(std::vector<double> & rData, NumericDataset * gData, CLEVER::Datasets::NumericDataset * repSet, int UseIndex = -1, int IndexVal = -1)
	{
		int nSize = rData.size(); //size of a cluster
		//int metasize = (int)rData->MetaData.data.size();
		int metasize = nSize;
		double nVal = 0;

		if (UseIndex > -1) { //index of cluster ID = UseIndex
			NumericDataset * medoid = repSet; new NumericDataset();

			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData[i] == IndexVal) {
					++nSize;
					//nVal += rData->GetMeta(i, 0);
					nVal += tDist->Distance(gData, i, medoid, IndexVal); //total distance from examples to the representative
				}
			}
			//delete medoid;
		} else   {
			for (int i = 0; i < metasize; ++i) {
				//if (UseIndex > -1 && (int)rData->GetMeta(i, UseIndex) != IndexVal)
				//{ continue; }
				nVal += gData->GetMeta(i, 0);
			}
		}


		double fitness = 0;
		double t = (double)nVal / (double)nSize; // t is the average distance between members to medoid

		if (t > rthreshold) {
			fitness = pP - t > 0 ? pP - t : 0; //fitness = Max(0, pP-avgDist)
			if (rEta != 1.0) { fitness = pow(fitness, rEta); }
		}

		return fitness;
	}


};

//! Custom interesting function for the sample application.
template<typename T>
class CustomInterestingFunc : public CLEVER::RegionDiscovery::Fitness::Additive::Interestingness<T>
{
	virtual double Fitness(CLEVER::Datasets::Dataset<T> * rData, int UseIndex = -1, int IndexVal = -1)
	{   //PROFILE_FUNC
		int nSize = rData->Size();
		int metasize = (int)rData->MetaData.data.size();
		double nVal = 0;

		if (UseIndex > -1) {
			nSize = 0;
			for (int i = 0; i < metasize; ++i) {
				if ((int)rData->GetMeta(i, UseIndex) == IndexVal) {
					++nSize;
					nVal += rData->GetMeta(i, 0);
				}
			}
		} else   {
			for (int i = 0; i < metasize; ++i) {
				//if (UseIndex > -1 && (int)rData->GetMeta(i, UseIndex) != IndexVal)
				//{ continue; }
				nVal += rData->GetMeta(i, 0);
			}
		}

		double fitness = 0;
		double t = (double)nVal / (double)nSize;
		if (t > rthreshold) {
			fitness = t - rthreshold;
			if (rEta != 1.0) { fitness = pow(fitness, rEta); }
		}

		return fitness;
	}


	virtual void Precompute(CLEVER::Datasets::Dataset<T> * rData)
	{   //PROFILE_FUNC

	}


};


//! Loads a dataset and its specification from file.
CLEVER::Datasets::NumericDataset * CreateDataset(char * dataspecFile, char * datasetFile)
{   //PROFILE_FUNC
	cout << "dataset file: " << datasetFile << endl << "data spec(.xml) file: " << dataspecFile << endl;
	cout << "Reading dataspec" << endl;
	//Formats::Dataspec spec("Oct27_DepthDataSpec.xml");
	CLEVER::Datasets::Dataspec * p_spec;
	//p_spec=new CLEVER::Datasets::Dataspec("10Oval.xml");
	//p_spec=new CLEVER::Datasets::Dataspec("Earthquake.xml");
	p_spec = new CLEVER::Datasets::Dataspec(dataspecFile);

	cout << "Reading dataset" << endl;
	NumericDataset * dataset = new NumericDataset();
	//DoubleArrayDataset* dataset = new DoubleArrayDataset();
	//dataset->LoadFromCSV("Oct27_FivePerEarthquakeSamplingTime1.csv", spec);
	//dataset->LoadFromCSV("10Ovals.csv", p_spec);
	//dataset->LoadFromCSV("EarthquakeFull.csv", p_spec);
	dataset->LoadFromCSV(datasetFile, p_spec);
	cout << "Loaded dataset" << endl;
	cout << "size: " << dataset->Size() << endl;
	return dataset;
}


CLEVER::Datasets::DoubleArrayDataset * CreateDoubleArrayDataset(char * dataspecFile, char * datasetFile, unsigned rNumExamples)
{   //PROFILE_FUNC
	cout << "dataset file: " << datasetFile << endl << "data spec(.xml) file: " << dataspecFile << endl;
	cout << "Reading dataspec" << endl;
	//Formats::Dataspec spec("Oct27_DepthDataSpec.xml");
	CLEVER::Datasets::Dataspec * p_spec;
	//p_spec=new CLEVER::Datasets::Dataspec("10Oval.xml");
	//p_spec=new CLEVER::Datasets::Dataspec("Earthquake.xml");
	p_spec = new CLEVER::Datasets::Dataspec(dataspecFile);

	cout << "Reading dataset" << endl;
	//NumericDataset* dataset = new NumericDataset();
	cout << "Create a DoubleArrayDataset" << endl;
	DoubleArrayDataset * dataset = new DoubleArrayDataset();
	cout << "Finished creating dataset container " << endl;
	//dataset->LoadFromCSV("Oct27_FivePerEarthquakeSamplingTime1.csv", spec);
	//dataset->LoadFromCSV("10Ovals.csv", p_spec);
	//dataset->LoadFromCSV("EarthquakeFull.csv", p_spec);
	cout << "Start loading csv file" << endl;
	dataset->LoadFromCSV(datasetFile, p_spec, rNumExamples);
	cout << "Loaded dataset" << endl;
	cout << "size: " << dataset->Size() << endl;
	return dataset;
}


//! Create the additive fitness function.
/*!
   \param tInterestingness Interestingness function.
   \param cluster_att Meta-index of the cluster attribute.
 */
Fitness::Additive::AdditiveFitnessFunction<double> * CreateFitnessFunction(Fitness::Additive::Interestingness<double> * tInterestingness, int cluster_att)
{
	return new Fitness::Additive::AdditiveFitnessFunction<double>(rbeta, tInterestingness, cluster_att);
}


//! Creates a neighbourhood for the sample application.
Neighbourhood * CreateNeighbourhood()
{
	std::vector<double> testprobs;
	testprobs.push_back(0.2);
	testprobs.push_back(0.2);
	testprobs.push_back(0.6);
	std::vector<enum OperatorBasedNeighbourhood::Operator> testops;
	testops.push_back(OperatorBasedNeighbourhood::OP_Insert);
	testops.push_back(OperatorBasedNeighbourhood::OP_Delete);
	testops.push_back(OperatorBasedNeighbourhood::OP_Replace);

	return new OperatorBasedNeighbourhood(testops, testprobs, 3);
}


//! Runs CLEVER with the specified random seed
/*!
   \param seed A seed for the random number generator.
 */


double RunWithSeed(char * dataSpecFile, char * datasetFile, unsigned int seed, CLEVER::RegionDiscovery::Clever::RunInfo * runinfo = 0)
{   //PROFILE_FUNC_ENABLE
	srand(seed);

	CLEVER::Datasets::Dataset<double> * dataset;
	DoubleArrayDataset * daDataset;
	//	if(interestingnessF.compare("AverageDistanceToMedoid")==0 )
	if (useDoubleArrayDataset) {
		//useDoubleArrayDataset=1;
		daDataset = CreateDoubleArrayDataset(dataSpecFile, datasetFile, _NumExamples); //earthquake: 330561
		//dataset = CreateDataset(dataSpecFile, datasetFile);
	} else   {
		//useDoubleArrayDataset=0;
		dataset = CreateDataset(dataSpecFile, datasetFile);
	}
	DistanceFunctions::MinkowskiDistanceFunction * distfunc =
	    new DistanceFunctions::MinkowskiDistanceFunction(2);
	Fitness::Additive::Interestingness<double> * tInterestingness;

	if (interestingnessF.compare("VarianceHigh") == 0) {
		VarianceHigh<double> * tInterestingness1 = new VarianceHigh<double>();
		tInterestingness1->DatasetVariance = 10210.92; //tInterestingness->FindVariance(dataset);
		tInterestingness = tInterestingness1;
	} else if (interestingnessF.compare("Purity") == 0) {
		//CustomInterestingFunc<double>* tInterestingness = new CustomInterestingFunc<double>();
		Fitness::Additive::Purity<double> * tInterestingness1 = new Fitness::Additive::Purity<double>();
		tInterestingness1->class_att = 0;
		tInterestingness1->eta = rEta;
		tInterestingness1->threshold = rthreshold;
		tInterestingness1->initialized = 1;
		tInterestingness = tInterestingness1;
	} else if (interestingnessF.compare("AverageDistanceToMedoid") == 0) {
		AverageDistanceToMedoid<double> * tInterestingness1 = new AverageDistanceToMedoid<double> (distfunc);
		tInterestingness = tInterestingness1;
		//isYahooDataset=true;
	}
	Fitness::Additive::AdditiveFitnessFunction<double> * ufit = CreateFitnessFunction(tInterestingness, clusterIDIndex);
	cout << "Created fitness" << endl;

	Neighbourhood * uneighbourhood = CreateNeighbourhood();
	cout << "Created neighbourhood" << endl;


	cout << "Creating search" << endl;
	DistanceFunctions::ProximitySearch<double> * proximitysearch =
	    new DistanceFunctions::LinearProximitySearch<double>(distfunc, false, true);

	if (useDistanceMatrix != 0) { //use distance matrix
		if (useDoubleArrayDataset == 0)
			proximitysearch->BuildDistanceMatrix(dataset);
		else
			proximitysearch->BuildDistanceMatrix(daDataset);
	}

	cout << "Created search" << endl;

	RegionDiscovery::Clever * clever;
	if (useDoubleArrayDataset == 1)
		clever = new RegionDiscovery::Clever(daDataset, clusterIDIndex, ufit, proximitysearch, distfunc, uneighbourhood, p, q, useDistanceMatrix, init_k, isLoopPara, maxTime, maxReplacement, incrementalUpdate);
	else
		clever = new RegionDiscovery::Clever(dataset, clusterIDIndex, ufit, proximitysearch, distfunc, uneighbourhood, p, q, useDistanceMatrix, init_k, isLoopPara, maxTime, maxReplacement, incrementalUpdate);
	//long t1 = GetTickCount();

	CStopWatch c;
	c.Start();
#ifdef EXTERN
#  ifdef FRAMEWORKPROFILER
	Profiler::Enable();
#  endif
#endif

	clever->Run(&c, runinfo);

#ifdef EXTERN
#  ifdef FRAMEWORKPROFILER
	Profiler::Disable();
#  endif
#endif

	c.Stop();
	//long tdiff = GetTickCount() - t1;
	double duration = c.GetDuration();
	if (runinfo) {
		runinfo->duration = duration;
	}
	/*
	    char out_filename[256];
	    sprintf_s(out_filename, 256, "Results_%u.csv", seed);
	 */
	std::stringstream Strm_out_filename;
	Strm_out_filename << datasetFile << "_OMP_" << omp_get_max_threads() << "_Results_" << seed << ".csv";
	/*
	    char out_filename_reps[256];
	    sprintf_s(out_filename_reps, 256, "Results_%u_reps.csv", seed);
	 */
	std::stringstream Strm_out_filename_reps;
	Strm_out_filename_reps << datasetFile << "_OMP_" << omp_get_max_threads() << "_Results_" << seed << "_reps.csv";


	if (useDoubleArrayDataset == 0)
		dataset->WriteToCSV(Strm_out_filename.str().c_str());
	else
		daDataset->WriteToCSV(Strm_out_filename.str().c_str());

	clever->FinalReps->WriteToCSV(Strm_out_filename_reps.str().c_str());
	//(Formats::Dataspec(dataset)).ToFile("Results_spec.xml");
	delete clever->FinalReps;
	delete clever;

	delete distfunc;
	proximitysearch->Release();
	delete proximitysearch;
	delete ufit;
	delete uneighbourhood;
	delete tInterestingness;
	if (useDoubleArrayDataset == 0)
		delete dataset;
	else
		delete daDataset;

#ifdef EXTERN
#  ifdef PROFILER
	Profiler::Disable();
#  endif
#endif

	return (double)duration;
}


//! Main test function for the CLEVER sample application.
int main(int argc, char * argv[])
{
#ifdef _DEBUG
	cout << "Warning: Running in Debug mode. This runs very slowly, so if you don't need the debugger, run in Release mode." << endl;
#endif

#ifdef EXTERN
#  ifdef FRAMEWORKPROFILER
	Debug::Initialize();
#  endif
#endif

	char * dataSpecFile = argv[2];
	char * datasetFile = argv[1];
	interestingnessF = string(argv[3]);
	p = atoi(argv[4]);
	q = atoi(argv[5]);
	rEta = atof(argv[6]);
	rthreshold = atof(argv[7]);
	rbeta = atof(argv[8]);
	useDistanceMatrix = atoi(argv[9]);
	clusterIDIndex = atoi(argv[10]);
	num_runs = atoi(argv[11]);
	useDoubleArrayDataset = atoi(argv[12]);
	_NumExamples = atol(argv[13]);
	init_k = atoi(argv[14]);
	isLoopPara = atoi(argv[15]);
	maxTime = atof(argv[16]);
	maxReplacement = atoi(argv[17]);
	incrementalUpdate = atoi(argv[18]);

	std::vector<double> timings;
	std::vector<CLEVER::RegionDiscovery::Clever::RunInfo> runinfo;
	for (int i = 0; i < num_runs; i++) {
		CLEVER::RegionDiscovery::Clever::RunInfo r;
		timings.push_back(RunWithSeed(dataSpecFile, datasetFile, i, &r)); //Experiment is executed here
		runinfo.push_back(r);
	}

#ifdef EXTERN
#  ifdef FRAMEWORKPROFILER
	Debug::Destroy();
#  endif
#endif

	for (unsigned int i = 0; i < timings.size(); i++) {
		cout << timings[i] << endl;
	}
	cout << "seed,k,evaluated neighbour solutions, duration, fitness, iterations" << endl;
	for (unsigned int i = 0; i < runinfo.size(); i++) {
		cout << i << ',' <<
		runinfo[i].k << ',' <<
		runinfo[i].iterations << ',' <<
		runinfo[i].duration << ',' <<
		runinfo[i].fitness << ',' <<
		runinfo[i].replacements << endl;
	}
	//cout << RunWithSeed(26) << endl;
	//RunWithSeed(463);
	//RunWithSeed(0);

	//system("pause");

	return 0;
}


/*! \mainpage CLEVER
 *
 * \section intro_sec Introduction
 *
 * This is the documentation for the C++ implementation of CLEVER written by Nauful Shaikh.
 *
 * \section start_sec Recommended starting points in the documentation
 *
 * Go to the sample application, main.cpp.
 *
 * View the algorithm in CLEVER::RegionDiscovery::Clever.
 *
 */
